﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using System.Threading;

namespace Generator.Tools
{
    public partial class WSTest : ToolsBase
    {

        private readonly string _testFileRoot = GlobalValues.CurrentPath + "\\WSTestFiles";

        public WSTest()
        {
            InitializeComponent();
        }


        private void AddFilesToTrees(TreeNode parentTreeNode, DirectoryInfo direcory)
        {
            foreach (DirectoryInfo di in direcory.GetDirectories())
            {
                var item = parentTreeNode.Nodes.Add(di.Name);
                item.ImageIndex = 0;
                AddFilesToTrees(item, di);
            }

            foreach (FileInfo fi in direcory.GetFiles("*.wst"))
            {
                var item = parentTreeNode.Nodes.Add(fi.Name);
                item.ImageIndex = 2;
                item.Tag = fi.FullName;
            }
        }

        private void ProcessPostData()
        {
            StringBuilder sb = new StringBuilder();
            foreach (var line in richTextBox2.Lines)
            {
                string[] strs = line.Split(new char[] { '&' });
                foreach (var str in strs)
                {
                    sb.AppendLine(str);
                }
            }

            richTextBox2.Text = sb.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            try
            {
                startRequest();
            }
            catch (Exception ex)
            {
                richTextBox1.AppendText(ex.ToString());
            }

        }

        private void startRequest()
        {
            richTextBox1.Clear();
            Dictionary<string, string> param = new Dictionary<string, string>();
            Dictionary<string, string> files = new Dictionary<string, string>();

            string[] s = new string[2];
            foreach (string header in richTextBox2.Lines)
            {
                s = header.Split(new char[] { '=' });
                if (s.Length == 2 && s[0].Length > 0)
                    param.Add(s[0], s[1]);
            }

            if (textBox2.Text.Trim().Length > 0)
            {
                param.Add("AttachFileName", new FileInfo(textBox2.Text).Name);
                files.Add("AttachFile", textBox2.Text);
            }
            richTextBox1.AppendText(PostDataWithFile(textBox1.Text, param, files));

        }


        private string PostDataWithFile(string url, Dictionary<string, string> param, Dictionary<string, string> files)
        {


            // 生成需要上传的二进制数组
            CreateBytes cb = new CreateBytes();
            // 所有表单数据
            ArrayList bytesArray = new ArrayList();
            foreach (var kv in param)
            {
                bytesArray.Add(cb.CreateFieldData(kv.Key, kv.Value));
            }
            // 文件表单
            foreach (var kv in files)
            {
                // 读文件流
                FileStream fs = new FileStream(kv.Value, FileMode.Open,
                                               FileAccess.Read, FileShare.Read);

                // 这部分需要完善
                string ContentType = "application/octet-stream";
                byte[] fileBytes = new byte[fs.Length];
                fs.Read(fileBytes, 0, Convert.ToInt32(fs.Length));

                bytesArray.Add(cb.CreateFieldData(kv.Key, kv.Value
                                                   , ContentType, fileBytes));
            }

            // 普通表单
            //			bytesArray.Add(cb.CreateFieldData("FileName", txtFilename.Text));
            //			bytesArray.Add(cb.CreateFieldData("AmigoToken", txtAmigoToken.Text));
            // 合成所有表单并生成二进制数组
            byte[] bytes = cb.JoinBytes(bytesArray);

            // 返回的内容
            byte[] responseBytes;
            // 上传到指定Url
            bool uploaded = cb.UploadData(url, bytes, out responseBytes);
            //return uploaded;

            string respHTML = System.Text.Encoding.UTF8.GetString(responseBytes);
            //respHTML = System.Web.HttpUtility.HtmlDecode(respHTML);
            return respHTML;

        }


        class CreateBytes
        {
            Encoding encoding = Encoding.UTF8;

            /**/
            /// <summary>
            /// 拼接所有的二进制数组为一个数组
            /// </summary>
            /// <param name="byteArrays">数组</param>
            /// <returns></returns>
            /// <remarks>加上结束边界</remarks>
            public byte[] JoinBytes(ArrayList byteArrays)
            {
                int length = 0;
                int readLength = 0;

                // 加上结束边界
                string endBoundary = Boundary + "--\r\n"; //结束边界
                byte[] endBoundaryBytes = encoding.GetBytes(endBoundary);
                byteArrays.Add(endBoundaryBytes);

                foreach (byte[] b in byteArrays)
                {
                    length += b.Length;
                }
                byte[] bytes = new byte[length];

                // 遍历复制
                //
                foreach (byte[] b in byteArrays)
                {
                    b.CopyTo(bytes, readLength);
                    readLength += b.Length;
                }

                return bytes;
            }

            public bool UploadData(string uploadUrl, byte[] bytes, out byte[] responseBytes)
            {
                WebClient webClient = new WebClient();
                webClient.Headers.Add("Content-Type", ContentType);

                try
                {
                    responseBytes = webClient.UploadData(uploadUrl, "POST", bytes);
                    return true;
                }
                catch (WebException ex)
                {
                    //				Stream resp = ex.Response.GetResponseStream();
                    //                responseBytes = new byte[ex.Response.ContentLength];
                    //                resp.Read(responseBytes, 0, responseBytes.Length);         
                    responseBytes = System.Text.Encoding.Default.GetBytes("{\"flag\":0,\"pic\":\"\"}");
                    throw ex;
                }
                return false;
            }



            /**/
            /// <summary>
            /// 获取普通表单区域二进制数组
            /// </summary>
            /// <param name="fieldName">表单名</param>
            /// <param name="fieldValue">表单值</param>
            /// <returns></returns>
            /// <remarks>
            /// -----------------------------7d52ee27210a3c\r\nContent-Disposition: form-data; name=\"表单名\"\r\n\r\n表单值\r\n
            /// </remarks>
            public byte[] CreateFieldData(string fieldName, string fieldValue)
            {
                string textTemplate = Boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n";
                string text = String.Format(textTemplate, fieldName, fieldValue);
                byte[] bytes = encoding.GetBytes(text);
                return bytes;
            }


            /**/
            /// <summary>
            /// 获取文件上传表单区域二进制数组
            /// </summary>
            /// <param name="fieldName">表单名</param>
            /// <param name="filename">文件名</param>
            /// <param name="contentType">文件类型</param>
            /// <param name="contentLength">文件长度</param>
            /// <param name="stream">文件流</param>
            /// <returns>二进制数组</returns>
            public byte[] CreateFieldData(string fieldName, string filename, string contentType, byte[] fileBytes)
            {
                string end = "\r\n";
                string textTemplate = Boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";

                // 头数据
                string data = String.Format(textTemplate, fieldName, filename, contentType);
                byte[] bytes = encoding.GetBytes(data);



                // 尾数据
                byte[] endBytes = encoding.GetBytes(end);

                // 合成后的数组
                byte[] fieldData = new byte[bytes.Length + fileBytes.Length + endBytes.Length];

                bytes.CopyTo(fieldData, 0); // 头数据
                fileBytes.CopyTo(fieldData, bytes.Length); // 文件的二进制数据
                endBytes.CopyTo(fieldData, bytes.Length + fileBytes.Length); // \r\n

                return fieldData;
            }



            #region 属性
            private string Boundary
            {
                get
                {
                    string[] bArray, ctArray;
                    string contentType = ContentType;
                    ctArray = contentType.Split(';');
                    if (ctArray[0].Trim().ToLower() == "multipart/form-data")
                    {
                        bArray = ctArray[1].Split('=');
                        return "--" + bArray[1];
                    }
                    return null;
                }
            }

            private string ContentType
            {
                get
                {
                    //if (HttpContext.Current == null)
                    //{
                    return "multipart/form-data; boundary=---------------------------7d5b915500cee";
                    //}
                    //return HttpContext.Current.Request.ContentType;
                }
            }
            #endregion
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.InitialDirectory = _testFileRoot;
            saveFileDialog1.FileName = GetNameFromUrl(textBox1.Text);
            var res = saveFileDialog1.ShowDialog();
            if (res != DialogResult.OK)
                return;

            try
            {
                if (File.Exists(saveFileDialog1.FileName))
                {
                    File.Delete(saveFileDialog1.FileName);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
                return;
            }
            try
            {
                using (var fs = File.Create(saveFileDialog1.FileName))
                {
                    StreamWriter streamWriter = new StreamWriter(fs);
                    streamWriter.WriteLine(textBox1.Text);
                    streamWriter.WriteLine(textBox2.Text);
                    streamWriter.Write(richTextBox2.Text);
                    streamWriter.Close();
                }

                refreshToolStripMenuItem_Click(sender, e);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
            }
        }

        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openFileDialog1.InitialDirectory = _testFileRoot;
            var res = openFileDialog1.ShowDialog();
            if (res != DialogResult.OK)
                return;

            OpenWsTestFile(openFileDialog1.FileName);
        }

        private void OpenWsTestFile(string fileName)
        {
            if (!File.Exists(fileName))
                return;

            textBox1.Text = "";
            textBox2.Text = "";
            richTextBox2.Text = "";
            richTextBox1.Text = "";

            try
            {
                using (var fs = File.OpenRead(fileName))
                {
                    StreamReader streamReader = new StreamReader(fs);
                    if (streamReader.Peek() > 0)
                    {
                        textBox1.Text = streamReader.ReadLine();
                    }
                    if (streamReader.Peek() > 0)
                    {
                        textBox2.Text = streamReader.ReadLine();
                    }
                    if (streamReader.Peek() > 0)
                    {
                        richTextBox2.Text = streamReader.ReadToEnd();
                    }
                    streamReader.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK);
            }
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            var res = openFileDialog2.ShowDialog();
            if (res != DialogResult.OK)
                return;
            textBox2.Text = openFileDialog2.FileName;
        }

        private void WSTest_Load(object sender, EventArgs e)
        {
            treeView1.Nodes.Add("WSTestRoot", "WSTest");
            LoadWsTestFiles();
        }

        private void LoadWsTestFiles()
        {
            if (!Directory.Exists(_testFileRoot))
            {
                Directory.CreateDirectory(_testFileRoot);
            }
            DirectoryInfo di = new DirectoryInfo(_testFileRoot);

            var treeNode = treeView1.TopNode;
            treeNode.Nodes.Clear();
            AddFilesToTrees(treeNode, di);
        }

        private void refreshToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadWsTestFiles();
        }

        private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Tag == null)
                return;

            OpenWsTestFile((string)e.Node.Tag);
        }

        private void richTextBox2_Leave(object sender, EventArgs e)
        {

        }

        private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            ProcessPostData();
        }

        private string GetNameFromUrl(string url)
        {
            Regex regex = new Regex(@"(?<=/Common/Execute\?fullTypeName=).*");
            var match = regex.Match(url);
            if (match.Success)
            {
                var strs = match.Value.Split(new char[] { '.' });
                if (strs.Length > 1)
                {
                    return strs[strs.Length - 1];
                }
                else
                {
                    return match.Value;
                }
            }
            else
            {
                return "";
            }

        }

        private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
        {
            checkSubNodes(e.Node, e.Node.Checked);
        }

        private void checkSubNodes(TreeNode node, bool isCheck)
        {
            foreach (TreeNode n in node.Nodes)
            {
                n.Checked = isCheck;
                if (n.Nodes.Count > 0)
                {
                    checkSubNodes(n, isCheck);
                }
            }

        }

        private void treeView1_AfterCollapse(object sender, TreeViewEventArgs e)
        {
            e.Node.ImageIndex = 0;
        }

        private void treeView1_AfterExpand(object sender, TreeViewEventArgs e)
        {
            e.Node.ImageIndex = 1;
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            e.Node.SelectedImageIndex = e.Node.ImageIndex;
        }


        delegate void delegate_OpenSubNodes(TreeNode node);

        private void batchToolStripMenuItem_Click(object sender, EventArgs e)
        {

            openSubNodes(treeView1.TopNode);

            //new Thread(() =>
            //{
            //    delegate_OpenSubNodes dg = new delegate_OpenSubNodes(openSubNodes);
            //    this.Invoke(dg, new object[] { treeView1.TopNode });
            //}).Start();
        }

        private void openSubNodes(TreeNode node)
        {
            foreach (TreeNode n in node.Nodes)
            {
                if (n.Nodes.Count > 0)
                {
                    openSubNodes(n);
                }
                else
                {
                    if (!n.Checked)
                        continue;

                    if (n.Tag != null)
                    {
                        n.ImageIndex = 3;
                        try
                        {
                            OpenWsTestFile((string)n.Tag);
                            startRequest();
                            n.ImageIndex = 4;
                        }
                        catch
                        {
                            n.ImageIndex = 5;
                        }
                    }


                }
            }

        }

    }
}
